unit NullableStrings;

interface

uses
  SysUtils, NullableTypes;

type
  NullableString = record
  private
    const C_INIT_VALUE: string = 'I'; 
    procedure SetIsNull(const AValue: Boolean);
    var FValue: string;
    var FInitFlag: string;
    procedure SetValue(const AValue: string);
    function GetValue: string;
    function GetIsNull: Boolean;
    procedure CheckValue;
  public
    procedure ClearValue;

    property Value: string read GetValue write SetValue;
    property IsNull: Boolean read GetIsNull write SetIsNull;

    class operator Implicit(a : string) : NullableString;
    class operator Implicit(a : NullableString) : string;

    class operator Add(a, b: NullableString): NullableString;
  end;

implementation

{ NullableString }

function NullableString.GetIsNull: boolean;
begin
  Result := FInitFlag <> C_INIT_VALUE;
end;

function NullableString.GetValue: string;
begin
  CheckValue;
  Result := FValue;
end;

procedure NullableString.SetValue(const AValue: string);
begin
  FInitFlag := C_INIT_VALUE;
  FValue := AValue;
end;

class operator NullableString.Implicit(a: NullableString): string;
begin
  Result := a.Value;
end;

class operator NullableString.Implicit(a: string): NullableString;
begin
  Result.Value := a;
end;

procedure NullableString.CheckValue;
begin
  if IsNull then
    raise ENullReference.Create('Attempted to read null as a value.');
end;

procedure NullableString.ClearValue;
begin
  FInitFlag := '';
  FValue := '';
end;

procedure NullableString.SetIsNull(const AValue: Boolean);
begin
  if not AValue then
    raise ENullReference.Create('Cannot convert a null value to non-null without providing a value!');
  ClearValue;
end;

class operator NullableString.Add(a, b: NullableString): NullableString;
begin
  Result.Value := a.Value + b.Value;
end;

end.


 
